import Modeler from 'bpmn-js/lib/Modeler';
import inherits from 'inherits';
import CustomTranslate from '@/bpmn/Modeler/customTranslate';
import CustomPalette from './Modeler/customPalette';
import CustomContextPad from './Modeler/customContextPad';
import CustomPopupMenu from "./Modeler/customPopupMenu";
import cmdHelper from '@/bpmn/Modeler/helper/CmdHelper';
import {getBusinessObject} from "bpmn-js/lib/util/ModelUtil";
import {getTimerDefinitionType} from "./util/common";

export default function CustomModeler(options) {
  Modeler.call(this, options);
  this.$v = options.$v;
  this.customElements = [];
  this.$element = null;
}

inherits(CustomModeler, Modeler);

CustomModeler.prototype.init = function(){
  this._bindEvents();
}

CustomModeler.prototype._modules = [].concat(CustomModeler.prototype._modules, [
  CustomTranslate,
  CustomPalette,
  CustomContextPad,
  CustomPopupMenu
]);

CustomModeler.prototype._bindEvents = function(){
  this.on('selection.changed', e => {
    const moddle = this.get("moddle");
    const curElement = e.newSelection[0];
    if(curElement){
      let element = e.newSelection[0];
      this.$v.bpmnElement = this.$element = element;
    }else{
      const rootElement = this.get("canvas").getRootElement();
      this.setCurrentElement(rootElement.type ? rootElement : this.$element)
    }
  });
  this.on("import.parse.complete", () => {
    setTimeout(() => {
      const elements = this.get("elementRegistry")._elements;
      for(let ele in elements){
        if(elements[ele].element.type === "bpmn:Process"){
          this.setCurrentElement(elements[ele].element);
        }
      }
    }, 10)
  });
}

CustomModeler.prototype.updateBusinessObject = function( businessObject, newProperties,element){
  const commandStack = this.get("commandStack");
  const command = cmdHelper.updateBusinessObject(element || this.$element, businessObject, newProperties);
  commandStack.execute(command.cmd, command.context);
}

CustomModeler.prototype.addElementsToList = function(extensionElements, key,value,element ){
  const commandStack = this.get("commandStack");
  const command = cmdHelper.addElementsTolist(element || this.$element, extensionElements, key, value);
  commandStack.execute(command.cmd, command.context);
}

CustomModeler.prototype.updateProperties = function( properties, element){
  const modeling = this.get("modeling");
  modeling.updateProperties(element || this.$element, properties)
}

CustomModeler.prototype.setCurrentElement = function(element){
  this.$v.bpmnElement = this.$element =element;
}

// 获取businessObject中的属性
CustomModeler.prototype.getProperty = function(property, element){
  const businessObject = getBusinessObject(element || this.$element)
  return businessObject[property];
}

// 更改多实例信息
CustomModeler.prototype.updateMultiInstanceProps = function(propertyName, val){
  const loopCharacteristics = this.getProperty("loopCharacteristics");
  const existingExpress = loopCharacteristics.get(propertyName);
  if(!existingExpress){
    const formalExpression = this.get("moddle").create("bpmn:FormalExpression", {body: val});
    formalExpression.$parent = loopCharacteristics;
    this.updateBusinessObject(loopCharacteristics, {[propertyName]: formalExpression});
  }else{
    this.updateBusinessObject(existingExpress, {body: val});
  }
}

CustomModeler.prototype.updateConditionProps = function(val){
  let conditionExpression = this.getProperty("conditionExpression");
  if(!conditionExpression){
    const formalExpression = this.get("moddle").create("bpmn:FormalExpression", {body: val});
    formalExpression.$parent = this.$element;
    conditionExpression = {conditionExpression: formalExpression};
    const businessObject = getBusinessObject(this.$element);
    this.updateBusinessObject(businessObject, conditionExpression);
  }else{
    this.updateBusinessObject(conditionExpression, {body: val});
  }
}

CustomModeler.prototype.updateTimerEventProps = function(data){
  const props = {
    timeDuration: undefined,
    timeDate: undefined,
    timeCycle: undefined
  };
  let eventDefinitions = this.getProperty("eventDefinitions")[0];
  if (!eventDefinitions) {
    eventDefinitions = this.get("moddle").create('bpmn:TimerEventDefinition');
  }
  if (data.type) {
    props[data.type] = this.get("moddle").create("bpmn:FormalExpression", {body: ""});
  }else{
    let oldType = getTimerDefinitionType(eventDefinitions);
    props[oldType] = this.get("moddle").create("bpmn:FormalExpression", {body: data.val});
  }
  this.updateBusinessObject(eventDefinitions, props);
}


CustomModeler.prototype.updateExtensionElements = function(val){
  const listeners = ["EventListener", "ExecutionListener", "TaskListener"];
  const commandStack = this.get("commandStack");
  let commands = [];
  let extensionElements = this.getProperty("extensionElements");
  if(!extensionElements){
    extensionElements = this.createElement("bpmn:ExtensionElements",{}, this.$element);
  }
  delete extensionElements.values;
  const extensionListeners = val.map(item => {
    const extensionListener =this.createElement("activiti:" + listeners[item.type - 1], {
      [item.listenerType.type]: item.listenerType.name,
      [item.type === 1 ? "events" : "event"]: item.eventName,
    }, extensionElements);
    if(item.fields){
      const fields = item.fields.map(field => {
        return this.createElement("activiti:Field", {name: field.name, [field.type]: field.value }, extensionListener)
      })
      commands.push(cmdHelper.addElementsTolist(this.$element, extensionListener, "fields", fields))
    }
    return extensionListener;
  })
  commands.push(cmdHelper.addElementsTolist(this.$element, extensionElements, "values", extensionListeners))
  commandStack.execute('properties-panel.multi-command-executor', commands);
  this.updateProperties({
    extensionElements
  })
}

CustomModeler.prototype.createExtensionElements = function(data){
  const commandStack = this.get("commandStack");
  let commands = [];
  let extensionElements = this.getProperty("extensionElements");
  if(!extensionElements){
    extensionElements = this.createElement("bpmn:ExtensionElements",{}, this.$element);
  }
  delete extensionElements.values;
  if(data){
    const elements = this.elementsRecursion(data, extensionElements, commands)
    commands.push(cmdHelper.addElementsTolist(this.$element, extensionElements, "values", elements))
  }
  commandStack.execute('properties-panel.multi-command-executor', commands);
  this.updateProperties({
    extensionElements
  })
}

CustomModeler.prototype.elementsRecursion = function(data, parent, commands){
  return data.map(item => {
    const element = this.createElement(item.elementName, item.properties, parent);
    if (item.children) {
      const children = this.elementsRecursion(item.children, element, commands)
      commands.push(cmdHelper.addElementsTolist(this.$element, element, item.propertyName, children))
    }
    return element
  })
}

// 创建元素
CustomModeler.prototype.createElement = function(elementType, properties, parent){
  const moddle = this.get("moddle");
  const element = moddle.create(elementType, properties);
  element.$parent = parent;
  return element;
}
//修改消息的参数事
CustomModeler.prototype.updateMessageEventProps = function(data){
  const props = {
    messageRef: null
  };
  let eventDefinitions = this.getProperty("eventDefinitions")[0];
  if (!eventDefinitions) {
    eventDefinitions = this.get("moddle").create('bpmn:MessageEventDefinition', props);
  }
  const  messageRef = eventDefinitions.get("messageRef");
  const definitions = this.getDefinitions();
  //如果已经存在，则删除旧的
  if (messageRef) {
    definitions.get("rootElements").forEach(function(item, index, arr) {
      if(item.get("id") == messageRef.get("id")) {
        definitions.get("rootElements").splice(index, 1);
      }
    });
  }
  const bpmnFactory = this.get('bpmnFactory');
  const messageId = data.val + "_"+ Date.now();
  const message = bpmnFactory.create('bpmn:Message', {id: messageId, name: data.val});
  definitions.get("rootElements").push(message);
  this.get("moddle").toXML(definitions).then(function (value){
    console.log(value)
  })
  props.messageRef = message;
  this.updateBusinessObject(eventDefinitions, props);
}

CustomModeler.prototype.createBusinessObjectList = function(element, currentObject, propertyName, newObjects ){
  const commandStack = this.get("commandStack");
  let commands = [];
  commands.push(cmdHelper.createBusinessObjectList((element, currentObject, propertyName, newObjects )));
  commandStack.execute('properties-panel.multi-command-executor', commands);
}